﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Xml;
using Microsoft.SharePoint;

namespace AVO
{
    [DataContract(Namespace = ContentTypeConfiguration.NameSpace)]
    public class ContentTypeConfiguration
    {
        internal const string NameSpace = "http://schemas.company.ru/sharepoint/v4/contenttype/avo";

        protected SPContentType m_ContentType = null;
        [DataMember]
        public bool Enabled { get; set; }

        [DataMember]
        public List<FieldVisibilityConfig> FieldConfigurations { get; set; }

        [DataMember]
        public string ContentTypeName { get; set; }

        public ContentTypeConfiguration()
        {
            FieldConfigurations = new List<FieldVisibilityConfig>();
        }

        public ContentTypeConfiguration(SPContentType ct)
            : this()
        {
            m_ContentType = ct;

            this.ContentTypeName = ct.Name;
        }

        public SPField GetSPField(Guid uid)
        {
            if (m_ContentType == null)
                throw new ArgumentNullException("m_ContentType");
            return m_ContentType.Fields[uid];
        }

        public FieldVisibilityConfig this[Guid fieldId]
        {
            get
            {
                return this.FieldConfigurations.FirstOrDefault(f => f.FieldId.Equals(fieldId));
            }
        }

        public void Save()
        {
            if (m_ContentType == null)
                throw new Exception("Content Type is not defined");


            SPSecurity.RunWithElevatedPrivileges(delegate()
            {
                Guid webid = m_ContentType.ParentWeb.ID;
                Guid siteid = m_ContentType.ParentWeb.Site.ID;
                Guid listId = m_ContentType.ParentList.ID;
                SPContentTypeId ctid = m_ContentType.Id;

                using (SPSite eSite = new SPSite(siteid))
                using (SPWeb eWeb = eSite.OpenWeb(webid))
                {
                    eWeb.AllowUnsafeUpdates = true;
                    SPList eList = eWeb.Lists[listId];
                    SPContentType ct = eList.ContentTypes[ctid];

                    try
                    {
                        ct.ParentWeb.AllowUnsafeUpdates = true;

                        string cfg = ct.XmlDocuments[NameSpace];
                        if (!string.IsNullOrEmpty(cfg))
                            ct.XmlDocuments.Delete(NameSpace);

                        DataContractSerializer dcs = new DataContractSerializer(typeof(ContentTypeConfiguration),
                            new Type[] { 
                                typeof(FieldVisibilityConfig)
                        });

                        StringBuilder sb = new StringBuilder();
                        using (XmlWriter xw = XmlWriter.Create(sb, new XmlWriterSettings() { OmitXmlDeclaration = true }))
                            dcs.WriteObject(xw, this);

                        XmlDocument xd = new XmlDocument();
                        xd.LoadXml(sb.ToString());

                        ct.XmlDocuments.Add(xd);
                        ct.Update();

                        bool isDocLib = eList.BaseTemplate == SPListTemplateType.PictureLibrary || eList.BaseTemplate == SPListTemplateType.DocumentLibrary;

                        string templateName = isDocLib ? "AVODocumentLibraryForm" : "AVOListForm";
                        string originaltemplateName = isDocLib ? "DocumentLibraryForm" : "ListForm";

                        // update content type for using advanced forms
                        ct.DisplayFormTemplateName =
                        ct.NewFormTemplateName =
                        ct.EditFormTemplateName = Enabled ? templateName : originaltemplateName;

                        ct.Update();
                    }
                    finally
                    {
                        eWeb.AllowUnsafeUpdates = false;
                    }

                }
            });
        }

        public void Load()
        {
            Load(false);
        }
        public void Load(bool updateIfnewFieldsDetected)
        {
            if (m_ContentType == null)
                throw new Exception("Content Type is not defined");

            SPSecurity.RunWithElevatedPrivileges(delegate()
            {
                Guid webid = m_ContentType.ParentWeb.ID;
                Guid siteid = m_ContentType.ParentWeb.Site.ID;
                Guid listId = m_ContentType.ParentList.ID;
                SPContentTypeId ctid = m_ContentType.Id;

                using (SPSite eSite = new SPSite(siteid))
                using (SPWeb eWeb = eSite.OpenWeb(webid))
                {
                    eWeb.AllowUnsafeUpdates = true;
                    SPList eList = eWeb.Lists[listId];
                    SPContentType ct = eList.ContentTypes[ctid];


                    string cfg = ct.XmlDocuments[NameSpace];
                    if (!string.IsNullOrEmpty(cfg))
                    {

                        DataContractSerializer dcs = new DataContractSerializer(typeof(ContentTypeConfiguration),
                            new Type[] { 
                            typeof(FieldVisibilityConfig)
                        });

                        ContentTypeConfiguration tmp = null;
                        using (XmlReader xr = XmlReader.Create(new StringReader(cfg)))
                        {
                            tmp = (ContentTypeConfiguration)dcs.ReadObject(xr);
                        }

                        if (tmp != null)
                        {
                            // shadow copy
                            this.Enabled = tmp.Enabled;
                            this.ContentTypeName = tmp.ContentTypeName;
                            this.FieldConfigurations = tmp.FieldConfigurations;
                        }
                    }

                    if (updateIfnewFieldsDetected)
                    {
                        bool bUpdateRequired = false;
                        foreach (SPField spf in ct.Fields)
                        {
                            bool bFoundDout = this.FieldConfigurations.Any(f => f.FieldId.Equals(spf.Id));
                            if (!bFoundDout)
                            {
                                bUpdateRequired = true;
                                this.FieldConfigurations.Add(
                                    new FieldVisibilityConfig()
                                    {
                                        FieldId = spf.Id,
                                        Enabled = false,
                                        FieldTitle = spf.Title,
                                        ScriptFunction = string.Empty
                                    });
                            }
                        }

                        if (bUpdateRequired)
                            Save();
                    }
                }
            });
        }
    }
}
